1 /***
2 * @version $Revision: 1.6 $
3 */
4 package uba.db.sql.interpreter;
5
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.List;
10
11 import uba.db.Database;
12 import uba.db.ar.Cartesiano;
13 import uba.db.ar.ConditionEvaluator;
14 import uba.db.ar.Proyector;
15 import uba.db.ar.ProyectorParameter;
16 import uba.db.ar.Seleccion;
17 import uba.db.ar.Tupla;
18 import uba.db.ar.TuplaDef;
19 import uba.db.ar.TupleProvider;
20 import uba.db.column.Column;
21 import uba.db.sql.language.Select;
22 import uba.db.sql.language.SelectionCriteria;
23 import uba.db.sql.language.TableName;
24 import uba.db.table.Table;
25
26 public class SelectQueryPlan implements SentenceQueryPlan {
27
28 private List tables;
29
30 private List columnsToProject;
31
32 private List columnsToEvaluate;
33
34 private Select sentence;
35
36 private SelectionCriteria selectionCriteria;
37
38 private TupleProvider executionResult;
39
40 private String planDetail;
41
42 private Database database;
43
44 public SelectQueryPlan(Select sqlSentence, Database database) {
45 tables = new ArrayList();
46 columnsToProject = new ArrayList();
47 columnsToEvaluate = new ArrayList();
48 sentence = sqlSentence;
49 selectionCriteria = sqlSentence.criteria();
50 this.database = database;
51 planDetail = "";
52 }
53
54
55
56
57 public void startExecution() {
58 sentence.source().accept(new TablesToJoinVisitor(this, database));
59 sentence.displayColumns().accept(new ColumnsToProjectVisitor(this));
60 sentence.criteria().accept(new ColumnsToEvaluateVisitor(this));
61
62 TupleProvider combinedTables = combine(tables);
63 TupleProvider selectedTuples = filter(combinedTables);
64 executionResult = project(selectedTuples);
65 }
66
67 public void addTable(Table table) {
68 tables.add(table);
69 }
70
71 private TupleProvider combineSigleTable(List tableNames) {
72 Table table = (Table) tables.get(0);
73 TupleProvider tupleProvider = new TableToTupleProviderAdapter(table);
74 planDetail += "Scan " + table.name() + "\t";
75 return tupleProvider;
76 }
77
78 private TupleProvider combineMultipleTables(List tableNames) {
79 Iterator it = tableNames.iterator();
80 Table firstTable = (Table) it.next();
81 TupleProvider combinedTable = new TableToTupleProviderAdapter(
82 firstTable);
83 Table nextTable;
84 TupleProvider nextTupleProvider;
85 planDetail += "Scan " + firstTable.name() + "\t";
86 while (it.hasNext()) {
87 nextTable = (Table) it.next();
88 planDetail += "Scan " + nextTable.name() + "\t";
89 nextTupleProvider = new TableToTupleProviderAdapter(nextTable);
90 combinedTable = new Cartesiano(combinedTable, nextTupleProvider);
91 planDetail += "Producto cartesiano " + combinedTable.toString()
92 + "\t";
93 }
94 return combinedTable;
95 }
96
97 /***
98 * Projecta. ES NECESARIO QUE EL ASTERISCO (*) SEA INTERPRETADO COMO "TODAS
99 * LAS COLUMNAS"
100 */
101 private TupleProvider project(TupleProvider tp) {
102 if (columnsToProject.isEmpty())
103 return tp;
104 else {
105 List indices = averiguarIndices();
106 planDetail += "Proyeccion " + columnsToProject.toString() + "\t";
107 return new Proyector(new ProyectorParameter(indices), tp);
108 }
109 }
110
111 /***
112 * @todo mejorar esta manera de detectar el null
113 */
114 private TupleProvider filter(TupleProvider tp) {
115 if (selectionCriteria.not() == selectionCriteria)
116 return tp;
117 else {
118 planDetail += "Filter " + selectionCriteria.toString() + "\t";
119 return filtered(tp);
120 }
121 }
122
123 public List tables() {
124 return tables;
125 }
126
127 private TupleProvider combine(List tableNames) {
128 if (tableNames.size() > 1)
129 return combineMultipleTables(tableNames);
130 else
131 return combineSigleTable(tableNames);
132 }
133
134 public Tupla nextTuple() {
135 return executionResult.next();
136 }
137
138 public String planDetail() {
139 return planDetail;
140 }
141
142 public boolean hasMoreResults() {
143 return executionResult.hasNext();
144 }
145
146 public void addColumnToProject(Column column) {
147 columnsToProject.add(column);
148 }
149
150 public Table tableNamed(TableName tableName) {
151 Iterator iterator = tables.iterator();
152 Table table = null;
153
154 while (iterator.hasNext() && table == null) {
155 Table eachTable = (Table) iterator.next();
156 if (eachTable.name().equalsIgnoreCase(tableName.toString())) {
157 table = eachTable;
158
159 }
160 }
161 return table;
162
163 }
164
165 private List averiguarIndices() {
166 Iterator iterator = columnsToProject.iterator();
167 List indices = new ArrayList();
168 while (iterator.hasNext()) {
169 Column column = (Column) iterator.next();
170 int index = column.table().indexOfColumnNamed(column.name());
171 int fieldsBefore = fieldsBeforeTableAt(indexOfTableOf(column
172 .table()));
173 indices.add(new Integer(fieldsBefore + index));
174 }
175 return indices;
176 }
177
178 private HashMap qualifiedColumnIndexes() {
179 Iterator iterator = columnsToEvaluate.iterator();
180 HashMap indexes = new HashMap();
181 while (iterator.hasNext()) {
182 Column column = (Column) iterator.next();
183 int index = column.table().indexOfColumnNamed(column.name());
184 int fieldsBefore = fieldsBeforeTableAt(indexOfTableOf(column
185 .table()));
186 indexes.put(column.table().name() + column.name(), new Integer(
187 fieldsBefore + index));
188 }
189 return indexes;
190 }
191
192 private int fieldsBeforeTableAt(int i) {
193 Table table;
194 int c;
195 c = 0;
196 for (int j = 0; j < i; j++) {
197 table = (Table) tables.get(j);
198 c += table.columns().size();
199 }
200 return c;
201 }
202
203 private int indexOfTableOf(Table table) {
204 return tables.indexOf(table);
205 }
206
207 private TupleProvider filtered(TupleProvider tp) {
208 HashMap indexes = qualifiedColumnIndexes();
209 ConditionEvaluator evaluator = new ConditionEvaluator(
210 selectionCriteria, indexes);
211 return new Seleccion(tp, evaluator);
212 }
213
214
215
216 public TuplaDef tuplaDefinition() {
217 return executionResult.tupleDefinition();
218 }
219
220 public void addColumnToEvaluate(Column column) {
221 columnsToEvaluate.add(column);
222 }
223
224 }